package com.vip.jwt.aop;

import cn.hutool.core.date.DateUtil;
import com.vip.jwt.common.utils.ClientUtil;
import com.vip.jwt.common.utils.JwtUtil;
import com.vip.jwt.config.JwtFilter;
import com.vip.jwt.entity.LoggerOperation;
import com.vip.jwt.service.LoggerOperationService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * @author lmk
 */
@Aspect
@Component
public class LogAspect {

	private static final Logger LOGGER = LoggerFactory.getLogger(LogAspect.class);

	private static final String AOP_POINTCUT_EXPRESSION = "execution(* com..controller..*.*(..)))";
	private static final String AOP_POINTCUT_EXPRESSION_LOGIN = "execution(* com..controller..*.login(..)))";
	private static final String AOP_POINTCUT_EXPRESSION_LOGOUT = "execution(* com..controller..*.logout(..)))";

	@Resource
	HttpServletRequest httpServletRequest;

	@Resource
	private LoggerOperationService loggerOperationService;

	@Autowired
	public LogAspect() {
	}

	@Pointcut(AOP_POINTCUT_EXPRESSION_LOGIN)
	public void loginPointcut() {}

	@Pointcut(AOP_POINTCUT_EXPRESSION_LOGOUT)
	public void logoutPointcut() {}

	@Pointcut(AOP_POINTCUT_EXPRESSION)
	public void logPointcut() {}

	@AfterReturning(value = "loginPointcut()")
	public void afterReturning() {
		//todo 登录
	}

	@Before("logoutPointcut()")
	public void doBefore() {
		//todo 退出
	}

	/**
	 * 用户操作日志记录
	 * @param point
	 * @return
	 * @throws Throwable
	 */
	@Around("logPointcut()")
	public Object doAround(ProceedingJoinPoint point) throws Throwable {
		Object result = point.proceed();
		String requestURI = httpServletRequest.getRequestURI();
		int login = requestURI.lastIndexOf("login");
		int logout = requestURI.lastIndexOf("logout");
		String method = httpServletRequest.getMethod();
		boolean flag = (login == -1 && logout == -1 && ("POST".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method) || "DELETE".equalsIgnoreCase(method)));
		if (flag) {
			//拦截了之后执行什么
			LoggerOperation operation = new LoggerOperation();
			operation.setUsername(getUsername());
			operation.setLogDesc(desc(point));
			operation.setMethod(method(point));
			operation.setParams(params(point));
			operation.setIp(ClientUtil.getClientIpAddress(httpServletRequest));
			operation.setLogTime(DateUtil.date());
			loggerOperationService.save(operation);
		}
		return result;
	}

	/**
	 * 方法出现异常日志记录
	 * @param point
	 * @param e
	 */
	@AfterThrowing(value = "logPointcut()", throwing = "e")
	public void doAfterThrowing(JoinPoint point, Throwable e) {
		LoggerOperation operation = new LoggerOperation();
		operation.setUsername(getUsername());
		operation.setLogDesc(desc(point));
		operation.setMethod(method(point));
		operation.setParams(params(point));
		// 捕获异常
		operation.setExceptionName(e.getClass().getName());
		operation.setExceptionMessage(e.getMessage());
		operation.setIp(ClientUtil.getClientIpAddress(httpServletRequest));
		operation.setLogTime(DateUtil.date());
		loggerOperationService.save(operation);
	}

	/**
	 * 获取切入点方法的描述
	 */
	private String desc(JoinPoint joinPoint) {
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Method method = signature.getMethod();
		SysLog log = method.getAnnotation(SysLog.class);
		if (log != null) {
			return log.desc();
		}
		return null;
	}

	/**
	 * 获取切入点方法
	 */
	private String method(JoinPoint joinPoint) {
		return joinPoint.getTarget().getClass().getName() + "."
				+ joinPoint.getSignature().getName() + getParamsTypeAndName(joinPoint);
	}

	/**
	 * 获取方法参数类型和名称
	 */
	private Object getParamsTypeAndName(JoinPoint joinPoint) {
		StringBuilder params = new StringBuilder("(");
		MethodSignature methodSignature = (MethodSignature) joinPoint
				.getSignature();
		String[] parameterNames = methodSignature.getParameterNames();
		Class<?>[] parameterTypes = methodSignature.getParameterTypes();
		if (parameterNames != null && parameterNames.length > 0
				&& parameterTypes != null && parameterTypes.length > 0) {
			for (int i = 0; i < joinPoint.getArgs().length; i++) {
				String type = parameterTypes[i].toString().substring(
						parameterTypes[i].toString().lastIndexOf(".") + 1);
				params.append(type).append(" ").append(parameterNames[i]).append(", ");
			}
			return params.substring(0, params.lastIndexOf(",")) + ")";
		} else {
			return "()";
		}
	}

	/**
	 * 获取参数内容
	 */
	private String params(JoinPoint joinPoint) {
		StringBuilder params = new StringBuilder("[");
		Object[] args = joinPoint.getArgs();
		if (args != null && args.length > 0) {
			for (Object arg : args) {
				if (arg != null) {
					params.append(arg.toString()).append(", ");
				} else {
					params.append(arg).append(", ");
				}
			}
			return params.substring(0, params.lastIndexOf(",")) + "]";
		} else {
			return "";
		}
	}

	/**
	 * 获取当前用户账户
	 */
//	private String getUsername() {
//		String username = null;
//		if (SecurityUtils.getSubject().isAuthenticated()) {
//			username = (String) SecurityUtils.getSubject().getPrincipal();
//		}
//		return username;
//	}

	/**
	 * 获取当前用户账户
	 */
	private String getUsername(){
		String authorization = JwtFilter.getAUTHORIZATION();
		String token = httpServletRequest.getHeader(authorization);
		return JwtUtil.getUsername(token);
	}

}